#pragma once
#include <string>
#include <memory>
#include <cstdio>
#include <errno.h>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "threadpool/Log.hpp"
#include "threadpool/Functions.hpp"
#include "threadpool/Thread_Pool.hpp"

#define ThreadNum 10

static void server(int fd, const std::string &src_ip, uint16_t src_port)
{
    char buffer[1024];
    while (true)
    {
        ssize_t sz = read(fd, buffer, sizeof(buffer));
        if (sz > 0)
        {
            buffer[sz] = 0;
            std::string str = "server回显:";
            str += buffer;
            // Messagelog(NORMAL, "[ %s | %d ] # %s\n", src_ip.c_str(), src_port, buffer);

            printf("[ %s | %d ] # %s\n", src_ip.c_str(), src_port, buffer);
            write(fd, str.c_str(), str.size());
        }
        else if (sz == 0)
        {
            // 读端关闭
            Messagelog(NORMAL, "客户端关闭");
            close(fd);
            break;
        }
        else
        {
            close(fd);
            Messagelog(ERROR, "服务器读到错误,ip:%s,port:%d", src_ip.c_str(), src_port);
            continue;
        }
    }
    close(fd);
}

struct ThreadData
{
    ThreadData(int fd, const std::string &ip, uint16_t port)
        : _fd(fd), _src_ip(ip), _src_port(port)
    {
    }

    int _fd;
    std::string _src_ip;
    uint16_t _src_port;
};

class TCP_server
{
private:
    static void *ThreadRoutine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *data = (ThreadData *)args;
        server(data->_fd, data->_src_ip, data->_src_port);
        delete data;
        return nullptr;
    }

public:
    TCP_server(uint16_t prot, const std::string &ip = "") 
        : _sock(-1), _prot(prot), _ip(ip), _threadpool_ptr(Thread_Pool<Task>::Creat_Threadpool(ThreadNum))
    {
    }

    bool serverinit()
    {
        // 创建socket
        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if (_sock < 0)
        {
            Messagelog(FATAL, "creat socket error:%d-%s", errno, strerror(errno));
            exit(2);
        }
        Messagelog(NORMAL, "socket creat success :%d", _sock);
        // bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_prot);
        // local.sin_addr.s_addr = inet_addr(_ip.c_str());
        local.sin_addr.s_addr = INADDR_ANY;
        socklen_t len = sizeof(local);
        if (bind(_sock, (struct sockaddr *)&local, len) < 0)
        {
            Messagelog(FATAL, "bind error:%d-%s", errno, strerror(errno));
            exit(3);
        }
        Messagelog(NORMAL, "socket bind success");

        // listen
        if (listen(_sock, 20) < 0)
        {
            Messagelog(FATAL, "listen error:%d-%s", errno, strerror(errno));
            exit(4);
        }
        Messagelog(NORMAL, "listen... ");
    }

    void start()
    {
        // signal(SIGCHLD, SIG_IGN);
        _threadpool_ptr->run(); // 只能run一次，run才是线程创建的时候
        while (true)
        {
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            int fd = accept(_sock, (struct sockaddr *)&src, &len);
            if (fd < 0)
            {
                Messagelog(ERROR, "connect fail:%d-%s", errno, strerror(errno));
                continue;
            }
            std::string src_ip = inet_ntoa(src.sin_addr);
            uint16_t src_port = ntohs(src.sin_port);

            Messagelog(NORMAL, "connect:[ %s | %d ]", src_ip.c_str(), src_port);
            // // 3.1 线程池版本
            Task task(fd, src_ip, src_port, server);
            _threadpool_ptr->push_task(task);
            

            // 3.0 多线程版
            // pthread 执行函数：类内定义static args：包含fd,src_ip,src_port
            // ThreadData *thread_data = new ThreadData(fd, src_ip, src_port);

            // pthread_t tid;
            // pthread_create(&tid, nullptr, ThreadRoutine, (void *)thread_data);

            // 2.1 多进程版，利用托孤
            // pid_t pid = fork();
            // if (pid == 0)
            // {
            //     // child
            //     close(_sock);
            //     if(fork() > 0) exit(0);
            //     // 孙子进程
            //     server(fd, src_ip, src_port);
            //     exit(0);// 一定要结束，不然就把整个逻辑又跑了一遍
            // }
            // close(fd);

            // 2.0 多进程版,配合信号
            // pid_t pid = fork();
            // if (pid == 0)
            // {
            //     // child
            //     close(_sock);
            //     server(fd, src_ip, src_port);
            //     exit(0);
            // }
            // close(fd);
            // 1. 文件读单进程，会导致同时只能和一个客户端通信的问题
            // server(fd, src_ip, src_port);
        }
    }

    ~TCP_server()
    {
        if (_sock > 0)
            close(_sock);
    }

private:
    int _sock;
    uint16_t _prot;
    std::string _ip;
    std::unique_ptr<Thread_Pool<Task>> _threadpool_ptr;
};